package com.dingreading.cloud.ssxcx.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.aliyun.MstCdnUtil;
import com.dingreading.cloud.ssxcx.dto.MembersDto;
import com.dingreading.cloud.ssxcx.dto.XcxStudentHomeworkDto;
import com.dingreading.cloud.ssxcx.entity.XcxHomeworkFiles;
import com.dingreading.cloud.ssxcx.entity.XcxHomeworkFilesTrack;
import com.dingreading.cloud.ssxcx.entity.XcxStudentHomework;
import com.dingreading.cloud.ssxcx.entity.XcxStudentLearningProgress;
import com.dingreading.cloud.ssxcx.entity.table.XcxStudentHomeworkTableDef;
import com.dingreading.cloud.ssxcx.mapper.XcxStudentHomeworkMapper;
import com.dingreading.cloud.ssxcx.service.XcxHomeworkFilesService;
import com.dingreading.cloud.ssxcx.service.XcxHomeworkFilesTrackService;
import com.dingreading.cloud.ssxcx.service.XcxStudentHomeworkService;
import com.dingreading.cloud.ssxcx.service.XcxStudentLearningProgressService;
import com.dingreading.cloud.ssxcx.util.DataProcessUtils;
import com.dingreading.cloud.ssxcx.util.XcxEntityUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 小程序学生课后作业表 服务层实现。
 *
 * @author EDY
 * @since 2025-08-15
 */
@Service
public class XcxStudentHomeworkServiceImpl extends BaseServiceImpl<XcxStudentHomeworkMapper, XcxStudentHomework, XcxStudentHomeworkTableDef> implements XcxStudentHomeworkService {
    @Resource
    private DataProcessUtils dataUtils;
    @Resource
    private XcxStudentLearningProgressService xcxLearningProgressService;
    @Resource
    private XcxHomeworkFilesService xcxHomeworkFilesService;
    @Resource
    private XcxHomeworkFilesTrackService xcxHomeworkFileTrackService;

    @Override
    protected XcxStudentHomeworkTableDef getTable() {
        return XcxStudentHomeworkTableDef.xcxStudentHomework;
    }

    @Override
    public R<Object> getBean(String agencyUid, String storeUid, String studentUid, String subjectLessonUid, String questionUid, String ip) {
        if (StringUtils.isEmpty(agencyUid)) return R.fail("伙伴uid为空！");
        if (StringUtils.isEmpty(storeUid)) return R.fail("门店uid为空！");
        if (StringUtils.isEmpty(studentUid)) return R.fail("学生uid为空！");
        if (StringUtils.isEmpty(subjectLessonUid)) return R.fail("课节uid为空！");
        if (StringUtils.isEmpty(questionUid)) return R.fail("课后题uid为空！");

        R<Object> ret = dataUtils.checkStudentUid(agencyUid, studentUid);
        if (R.isError(ret)) return ret;

        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.agencyUid.eq(agencyUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.studentUid.eq(studentUid))
                .and(table.subjectLessonUid.eq(subjectLessonUid))
                .and(table.questionUid.eq(questionUid))
                .and(table.enabled.eq(1));
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc())
                .limit(1);

        XcxStudentHomeworkDto homework = getMapper().selectOneWithRelationsByQueryAs(queryWrapper, XcxStudentHomeworkDto.class);
        if (homework != null && CollectionUtils.isNotEmpty(homework.getHomeworkImageUrls())) {
            long expire = MstCdnUtil.getImgExpire();
            List<String> cdnImageUrls = homework.getHomeworkImageUrls().stream()
                    .map((String url) -> dataUtils.getXcxUrl(url, ip, expire))
                    .collect(Collectors.toList());
            homework.setHomeworkImageUrls(cdnImageUrls);
        }
        return R.ok(homework);
    }

    @Override
    public R<Object> getBeanStatus(String agencyUid, String storeUid, String studentUid, String subjectLessonUid, String questionUid) {
        if (StringUtils.isEmpty(agencyUid)) return R.fail("伙伴uid为空！");
        if (StringUtils.isEmpty(storeUid)) return R.fail("门店uid为空！");
        if (StringUtils.isEmpty(studentUid)) return R.fail("学生uid为空！");
        if (StringUtils.isEmpty(subjectLessonUid)) return R.fail("课节uid为空！");
        if (StringUtils.isEmpty(questionUid)) return R.fail("课后题uid为空！");

        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.agencyUid.eq(agencyUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.studentUid.eq(studentUid))
                .and(table.subjectLessonUid.eq(subjectLessonUid))
                .and(table.questionUid.eq(questionUid))
                .and(table.enabled.eq(1));
        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.status)
                .where(condition)
                .orderBy(table.id.desc())
                .limit(1);

        Integer status = getMapper().selectOneByQueryAs(wrapper, Integer.class);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status", NepUtil.nullToZero(status));
        return R.ok(jsonObject);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R<Object> uploadHomework(
            String agencyUid, String storeUid, String studentUid,
            String subjectLessonUid, String questionUid, String uid, List<String> imageUrls
    ) {
        // 1. 参数校验
        if (StringUtils.isEmpty(agencyUid)) return R.fail("伙伴uid为空！");
        if (StringUtils.isEmpty(storeUid)) return R.fail("门店uid为空！");
        if (StringUtils.isEmpty(studentUid)) return R.fail("学生uid为空！");
        if (StringUtils.isEmpty(subjectLessonUid)) return R.fail("课节uid为空！");
        if (StringUtils.isEmpty(questionUid)) return R.fail("课后题uid为空！");
        if (CollectionUtils.isEmpty(imageUrls)) return R.fail("作业图片urls集合为空！");

        Date nowDatetime = DateUtil.getNowDatetime();
        R<Object> ret = dataUtils.checkStudentUid(agencyUid, studentUid);
        if (R.isError(ret)) return ret;
        MembersDto membersDto = (MembersDto) ret.getData();
        String studentName = membersDto.getMemberName();
        String phone = membersDto.getMob();
        String versionUid = KitUtil.getUuid();

        // 2. 判断是更新还是新增
        if (StringUtils.isNotBlank(uid)) {

            QueryCondition condition = QueryCondition.createEmpty()
                    .and(table.uid.eq(uid))
                    .and(table.studentUid.eq(studentUid))
                    .and(table.subjectLessonUid.eq(subjectLessonUid))
                    .and(table.questionUid.eq(questionUid));

            XcxStudentHomework existingHomework = getMapper().selectOneByCondition(condition);

            if (existingHomework == null) return R.fail("指定的作业记录不存在！");
            if (existingHomework.getEnabled().equals(0)) return R.fail("指定的作业记录已更新！");

            // 如果作业已批改，不允许修改
            if (existingHomework.getStatus() != null && existingHomework.getStatus() != 1) { // 1-已提交/待批改
                return R.fail("该作业已批改，无法直接修改!");
            }

            boolean updateHomeworkFilesTrack = dealHomeworkFilesTrack(existingHomework, imageUrls, studentUid, studentName);
            if (!updateHomeworkFilesTrack) {
                throw new RuntimeException("地址跟踪更新失败！");
            }
            // 删除原先作业
            Boolean deleteHomeworkUid = xcxHomeworkFilesService.deleteByHomeworkUid(existingHomework);
            if (!deleteHomeworkUid) {
                throw new RuntimeException("作业图片删除失败！");
            }
            List<XcxHomeworkFiles> homeworkFiles = XcxEntityUtils.newHomeworkFiles(existingHomework, imageUrls, versionUid);
            boolean saveHomeworkFiles = xcxHomeworkFilesService.saveBatch(homeworkFiles);
            if (!saveHomeworkFiles) {
                throw new RuntimeException("作业图片保存失败！");
            }

            boolean updateByHomeworkUid = xcxLearningProgressService.updateByHomeworkUid(existingHomework, versionUid);
            if (!updateByHomeworkUid) {
                throw new RuntimeException("课后作业版本号失败！");
            }

            existingHomework.setSubmissionTime(nowDatetime);
            existingHomework.setVersionUid(versionUid);
            existingHomework.setLastStaffUid(studentUid);
            existingHomework.setLastStaffName(studentName);
            boolean success = updateById(existingHomework);
            if (!success) {
                throw new RuntimeException("作业保存失败！");
            }
        } else {
            QueryCondition condition = QueryCondition.createEmpty()
                    .and(table.studentUid.eq(studentUid))
                    .and(table.subjectLessonUid.eq(subjectLessonUid))
                    .and(table.questionUid.eq(questionUid))
                    .and(table.enabled.eq(1));

            QueryWrapper queryWrapper = QueryWrapper.create()
                    .where(condition)
                    .orderBy(table.id.desc())
                    .limit(1);

            XcxStudentHomework lastHomework = getMapper().selectOneByQuery(queryWrapper);

            if (lastHomework != null && lastHomework.getStatus() != null) {
                if (lastHomework.getStatus() == 1)
                    return R.fail("课后作业已提交未批改，请勿重复提交！");
                if (lastHomework.getStatus() == 2)
                    return R.fail("课后作业已批改通过，请勿重复提交！");
                if (lastHomework.getStatus() == -1) {
                    lastHomework.setEnabled(0);
                    boolean updayeLastHomework = updateById(lastHomework);
                    if (!updayeLastHomework) {
                        throw new RuntimeException("更新历史作业失败！");
                    }
                }
            }

            Map<String, String> materialUids = dataUtils.getLessonMaterialUids(subjectLessonUid, MstXcxClassType.AFTERCLASS.getType());

            String projectUid = materialUids.get(DataProcessUtils.KEY_PROJECT_UID);
            String stageUid = materialUids.get(DataProcessUtils.KEY_STAGE_UID);

            XcxStudentHomework newHomework = XcxEntityUtils.createNewHomework(
                    agencyUid, storeUid, studentUid, studentName, phone, subjectLessonUid,
                    questionUid, nowDatetime, projectUid, stageUid, versionUid
            );

            List<XcxHomeworkFiles> homeworkFiles = XcxEntityUtils.newHomeworkFiles(newHomework, imageUrls, versionUid);
            boolean saveHomeworkFiles = xcxHomeworkFilesService.saveBatch(homeworkFiles);
            if (!saveHomeworkFiles) {
                throw new RuntimeException("作业图片保存失败！");
            }

            boolean updateFilesTrack = updateFilesTrack(imageUrls, newHomework);
            if (!updateFilesTrack) {
                throw new RuntimeException("地址跟踪更新失败！");
            }

            boolean success = save(newHomework);
            if (!success) {
                throw new RuntimeException("保存新记录失败！");
            }

            XcxStudentLearningProgress progress = XcxEntityUtils.newProgressBean(
                    agencyUid, storeUid, studentUid, studentName, phone, questionUid, newHomework.getUid(),
                    null, subjectLessonUid, MstXcxClassType.AFTERCLASS.getType(), projectUid, stageUid, versionUid
            );
            boolean saveProgress = xcxLearningProgressService.save(progress);
            if (!saveProgress) {
                throw new RuntimeException("保存学习轨迹失败！");
            }
        }
        return R.ok();
    }

    @Override
    public Page<XcxStudentHomeworkDto> pageListHomework(PageUtil pageUtil, String agencyUid, String storeUid, String studentUid, String projectUid) {
        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.agencyUid.eq(agencyUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.studentUid.eq(studentUid));
        if (StringUtils.isNotBlank(projectUid)) {
            condition.and(table.projectUid.eq(projectUid));
        }
        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());
        return getMapper().paginateWithRelationsAs(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper, XcxStudentHomeworkDto.class);
    }

    @Override
    public R<Object> getOssHomework(String fileType) {
        return dataUtils.getOssSts(fileType);
    }

    @Override
    public R<Object> getHomeworkUrl(String url, String ip) {
        long expire = MstCdnUtil.getImgExpire();
        return R.ok(dataUtils.getXcxUrl(url, ip, expire));
    }

    public boolean dealHomeworkFilesTrack(XcxStudentHomework homework, List<String> newImageUrls, String studentUid, String studentName) {
        // 1. 获取当前作业旧的图片URL集合
        Set<String> oldUrls = xcxHomeworkFilesService.getByHomeworkUid(homework.getUid()).stream()
                .map(XcxHomeworkFiles::getUrl)
                .collect(Collectors.toSet());

        Set<String> newUrls = new HashSet<>(newImageUrls);

        // 2. 计算差异：找出不再使用的URL和新增加的URL
        // 不再使用的 = 存在于旧集合，但不存在于新集合 (removed)
        Set<String> removedUrls = new HashSet<>(oldUrls);
        removedUrls.removeAll(newUrls);

        // 新增加的 = 存在于新集合，但不存在于旧集合 (added)
        Set<String> addedUrls = new HashSet<>(newUrls);
        addedUrls.removeAll(oldUrls);

        if (removedUrls.isEmpty() && addedUrls.isEmpty()) {
            // 如果URL列表没有任何变化，直接返回
            return true;
        }

        List<XcxHomeworkFilesTrack> tracksToUpdate = new ArrayList<>();

        // 3. 处理与当前作业“解除关联”的URL所对应的Track记录
        processTracksForRemovedUrls(removedUrls, tracksToUpdate, studentUid, studentName);

        // 4. 处理“新关联”到当前作业的URL所对应的Track记录
        processTracksForAddedUrls(addedUrls, tracksToUpdate, homework.getUid(), homework.getSubjectLessonUid(), studentUid, studentName);

        // 5. 如果有需要更新的记录，执行一次性批量更新
        if (!tracksToUpdate.isEmpty()) {
            // 使用Map根据ID去重，确保每个track只更新一次
            Map<Long, XcxHomeworkFilesTrack> finalUpdateMap = tracksToUpdate.stream()
                    .collect(Collectors.toMap(
                            XcxHomeworkFilesTrack::getId, // 假设Track对象有唯一的ID
                            track -> track,
                            (existing, replacement) -> replacement // 如果key重复，保留后者
                    ));
            xcxHomeworkFileTrackService.updateBatch(new ArrayList<>(finalUpdateMap.values()));
        }

        return true;
    }

    /**
     * 处理因图片与当前作业解除关联而需要更新的Track记录。
     * 逻辑：如果一个文件不再被这份作业使用，需要检查使用该文件的其他作业的状态，
     * 并据此更新Track的状态。例如，如果还有其他“已完成”的作业在使用它，
     * 则将这个文件的Track状态更新为1。
     *
     * @param removedUrls    不再被当前作业使用的图片URL集合
     * @param tracksToUpdate 待更新的Track记录列表
     * @param studentUid
     * @param studentName
     */
    private void processTracksForRemovedUrls(Set<String> removedUrls, List<XcxHomeworkFilesTrack> tracksToUpdate, String studentUid, String studentName) {
        if (CollectionUtils.isEmpty(removedUrls)) {
            return;
        }

        // 查找与这些URL相关的所有Track记录
        List<XcxHomeworkFilesTrack> tracksForRemovedUrls = xcxHomeworkFileTrackService.getByFileUrls(new ArrayList<>(removedUrls));
        if (CollectionUtils.isEmpty(tracksForRemovedUrls)) {
            return;
        }

        // 获取这些Track记录关联的所有作业UID
        Set<String> relatedHomeworkUids = tracksForRemovedUrls.stream()
                .map(XcxHomeworkFilesTrack::getHomeworkUid)
                .collect(Collectors.toSet());

        // 一次性查询出所有关联作业中状态为1 (假设1代表未批改) 的作业UID
        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.uid.in(relatedHomeworkUids))
                .and(table.status.eq(1));
        Set<String> activeHomeworkUids = getMapper().selectListByCondition(condition).stream()
                .map(XcxStudentHomework::getUid)
                .collect(Collectors.toSet());

        // 遍历需要处理的Track，如果其关联的作业是“活跃”的，则更新状态
        for (XcxHomeworkFilesTrack track : tracksForRemovedUrls) {
            if (activeHomeworkUids.contains(track.getHomeworkUid()) && track.getStatus() != 1) {
                track.setStatus(1);
                track.setLastStaffUid(studentUid);
                track.setLastStaffName(studentName);
                tracksToUpdate.add(track);
            }
        }
    }

    /**
     * 处理新关联到当前作业的图片URL所对应的Track记录。
     * 逻辑：新关联到这份作业的图片，其Track状态应更新为2 (假设2代表正在使用/待处理)。
     *
     * @param addedUrls      新增加的图片URL集合
     * @param tracksToUpdate 待更新的Track记录列表
     * @param studentUid
     * @param studentName
     */
    private void processTracksForAddedUrls(
            Set<String> addedUrls, List<XcxHomeworkFilesTrack> tracksToUpdate,
            String homeworkUid, String subjectLessonUid, String studentUid, String studentName
    ) {
        if (CollectionUtils.isEmpty(addedUrls)) {
            return;
        }

        // 查找与新增URL相关的所有Track记录
        List<XcxHomeworkFilesTrack> tracksForAddedUrls = xcxHomeworkFileTrackService.getByFileUrls(new ArrayList<>(addedUrls));

        // 将这些新关联文件的Track状态更新为2
        for (XcxHomeworkFilesTrack track : tracksForAddedUrls) {
            if (track.getStatus() != 2) {
                track.setStatus(2);
                track.setStudentUid(studentUid);
                track.setSubjectLessonUid(subjectLessonUid);
                track.setHomeworkUid(homeworkUid);
                track.setAddStaffUid(studentUid);
                track.setAddStaffName(studentName);
                track.setLastStaffUid(studentUid);
                track.setLastStaffName(studentName);
                tracksToUpdate.add(track);
            }
        }
    }

    public boolean updateFilesTrack(List<String> imageUrls, XcxStudentHomework homework) {
        List<XcxHomeworkFilesTrack> filesTrackList = xcxHomeworkFileTrackService.getByFileUrls(imageUrls);
        if (CollectionUtils.isNotEmpty(filesTrackList)) {
            for (XcxHomeworkFilesTrack filesTrack : filesTrackList) {
                if (filesTrack.getStatus() == 1) {
                    filesTrack.setStatus(2);
                    filesTrack.setStudentUid(homework.getStudentUid());
                    filesTrack.setSubjectLessonUid(homework.getSubjectLessonUid());
                    filesTrack.setHomeworkUid(homework.getUid());
                    filesTrack.setAddStaffUid(homework.getAddStaffUid());
                    filesTrack.setAddStaffName(homework.getAddStaffName());
                    filesTrack.setLastStaffUid(homework.getLastStaffUid());
                    filesTrack.setLastStaffName(homework.getLastStaffName());
                }
            }
            return xcxHomeworkFileTrackService.saveOrUpdateBatch(filesTrackList);
        }
        return true;
    }

}
